package com.ruoyi.gis.service.impl;

import java.io.IOException;
import java.net.MalformedURLException;
import java.util.List;

import cn.hutool.core.util.IdUtil;
import com.alibaba.fastjson2.JSON;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.framework.gis.GeoserverConfig;
import com.ruoyi.gis.geoserver.domain.GeoServerLayer;
import com.ruoyi.gis.geoserver.domain.GroupBounds;
import com.ruoyi.gis.geoserver.service.GeoserverService;
import com.ruoyi.gis.domain.GeoLayer;
import com.ruoyi.gis.domain.ImportLayerVo;
import com.ruoyi.gis.vo.ClassStyle;
import com.ruoyi.gis.vo.RasterStyleConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.gis.mapper.GisLayerMapper;
import com.ruoyi.gis.domain.GisLayer;
import com.ruoyi.gis.service.IGisLayerService;

/**
 * 图层管理Service业务层处理
 *
 * @author rww
 * @date 2023-02-27
 */
@Service
public class GisLayerServiceImpl implements IGisLayerService
{
    @Autowired
    private GisLayerMapper gisLayerMapper;
    @Autowired
    private GeoserverService geoserverService;
    @Autowired
    private GeoserverConfig geoserverConfig;
    /**
     * 查询图层管理
     *
     * @param layerId 图层管理主键
     * @return 图层管理
     */
    @Override
    public GisLayer selectGisLayerByLayerId(Long layerId)
    {
        return gisLayerMapper.selectGisLayerByLayerId(layerId);
    }

    /**
     * 查询图层管理列表
     *
     * @param gisLayer 图层管理
     * @return 图层管理
     */
    @Override
    public List<GisLayer> selectGisLayerList(GisLayer gisLayer)
    {
        return gisLayerMapper.selectGisLayerList(gisLayer);
    }

    /**
     * 新增图层管理
     *
     * @param gisLayer 图层管理
     * @return 结果
     */
    @Override
    public int insertGisLayer(GisLayer gisLayer)
    {
        gisLayer.setCreateTime(DateUtils.getNowDate());
        gisLayer.setLayerId(IdUtil.getSnowflakeNextId());
        if(gisLayer.getParentId()==null||gisLayer.getParentId()==0){
            gisLayer.setParentId(0L);
            gisLayer.setAncestors("0,"+gisLayer.getLayerId()+",");
        }else {
            GisLayer parent = selectGisLayerByLayerId(gisLayer.getParentId());
            if(parent!=null){
                gisLayer.setAncestors(parent.getAncestors()+gisLayer.getLayerId()+",");
            }
        }
        gisLayer.setStatus("1");
        gisLayer.setDelFlag("0");
        return gisLayerMapper.insertGisLayer(gisLayer);
    }

    /**
     * 修改图层管理
     *
     * @param gisLayer 图层管理
     * @return 结果
     */
    @Override
    public int updateGisLayer(GisLayer gisLayer)
    {
        gisLayer.setUpdateTime(DateUtils.getNowDate());
        return gisLayerMapper.updateGisLayer(gisLayer);
    }

    /**
     * 批量删除图层管理
     *
     * @param layerIds 需要删除的图层管理主键
     * @return 结果
     */
    @Override
    public int deleteGisLayerByLayerIds(Long[] layerIds)
    {
        return gisLayerMapper.deleteGisLayerByLayerIds(layerIds);
    }

    /**
     * 删除图层管理信息
     *
     * @param layerId 图层管理主键
     * @return 结果
     */
    @Override
    public int deleteGisLayerByLayerId(Long layerId)
    {
        return gisLayerMapper.deleteGisLayerByLayerId(layerId);
    }

    @Override
    public boolean hasChildByLayerId(Long layerId) {
        int result = gisLayerMapper.hasChildByLayerId(layerId);
        return result > 0;
    }

    @Override
    public GisLayer selectGisLayerBySourceUrl(String sourceUrl) {
        return gisLayerMapper.selectGisLayerBySourceUrl(sourceUrl);
    }

    @Override
    public GisLayer selectGisLayerByBzid(String bzid) {
        GisLayer gisLayer = gisLayerMapper.selectGisLayerByBzid(bzid);
        return gisLayer;
    }

    @Override
    public GisLayer selectGisLayerByFileId(Long fileId) {
        GisLayer gisLayer = gisLayerMapper.selectGisLayerByFileId(fileId);
        return gisLayer;
    }

    @Override
    public void updateParentBoundary(Long layerId) {
        if(layerId==0)return;
        GisLayer query = new GisLayer();
        query.setParentId(layerId);
        List<GisLayer> gisLayers = selectGisLayerList(query);
        if(gisLayers==null)return;
        GroupBounds groupBounds = new GroupBounds();
        groupBounds.setMaxy(-90);
        groupBounds.setMaxx(-180);
        groupBounds.setMiny(90);
        groupBounds.setMinx(180);
        gisLayers.stream().forEach(item->{
            try {
                if(item.getBoundary()!=null){
                    GroupBounds bounds = JSON.parseObject(item.getBoundary(),GroupBounds.class);
                    if(groupBounds.getMaxx()<bounds.getMaxx()){
                        groupBounds.setMaxx(bounds.getMaxx());
                    }
                    if(groupBounds.getMaxy()<bounds.getMaxy()){
                        groupBounds.setMaxy(bounds.getMaxy());
                    }
                    if(groupBounds.getMinx()>bounds.getMinx()){
                        groupBounds.setMinx(bounds.getMinx());
                    }
                    if(groupBounds.getMiny()>bounds.getMiny()){
                        groupBounds.setMiny(bounds.getMiny());
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
        GisLayer gisLayer = selectGisLayerByLayerId(layerId);
        gisLayer.setBoundary(JSON.toJSONString(groupBounds));
        gisLayerMapper.updateGisLayer(gisLayer);
        updateParentBoundary(gisLayer.getParentId());
    }

    @Override
    public void deleteGisLayerGroupByFileId(Long fileId) {
        gisLayerMapper.deleteGisLayerGroupByFileId(fileId);
    }

    @Override
    public void importGeoserverLayer(ImportLayerVo importLayerVo, LoginUser loginUser) {

        GeoLayer layer = null;
        GeoServerLayer layerConfig = null;
        try {
            String wsAndLayer = importLayerVo.getWorkspace()+":"+importLayerVo.getLayerName();
            //logger.info("publish layer ok  will   getLayerConfig .......");
            layerConfig = geoserverService.getLayerConfig(wsAndLayer);
            if (layerConfig != null) {
                layer = geoserverService.getLayer(importLayerVo.getWorkspace(), importLayerVo.getLayerName());
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        if(layer==null)return;
        GisLayer subLayer = new GisLayer();
        subLayer.setLayerId(IdUtil.getSnowflakeNextId());
        subLayer.setUserId(loginUser.getUserId());
        subLayer.setBzid(layerConfig.getId());
        subLayer.setSourceUrl(layer.getSourceUrl());
        subLayer.setLayerTitle(layer.getTitle());//(StringUtils.isEmpty(layer.getTitle()) ? layerTitle : layer.getTitle());
        subLayer.setLayerStyle(layer.getStyle());
        subLayer.setEndpoint(geoserverConfig.getEndpoint());
        subLayer.setLayerName(layer.getName());
        subLayer.setGroup(GisLayer.type_layer);//图层
        if(importLayerVo.getParentId()==0){
            GisLayer parentGislayer = null;
            subLayer.setParentId(parentGislayer!=null?parentGislayer.getLayerId():0L);
            subLayer.setAncestors(parentGislayer!=null?
                    parentGislayer.getAncestors() + subLayer.getLayerId() + ",":"0,"+ subLayer.getLayerId() + ",");
        }else {
            GisLayer parentGislayer = selectGisLayerByLayerId(importLayerVo.getParentId());
            subLayer.setParentId(importLayerVo!=null?parentGislayer.getLayerId():0L);
            subLayer.setAncestors(parentGislayer!=null?
                    parentGislayer.getAncestors() + subLayer.getLayerId() + ",":"0,"+ subLayer.getLayerId() + ",");
        }
        //subLayer.setFileId(tblFile.getId());
        subLayer.setWorkspace(importLayerVo.getWorkspace());
        subLayer.setStatus("1");
        subLayer.setCrs(layer.getCrs());
        subLayer.setDelFlag("0");
        subLayer.setSourceType(layer.getType());
        subLayer.setLayerType(layer.getType());
        String bounds = JSON.toJSONString(layer.getBoundary());
        subLayer.setBoundary(bounds);
        String[] mimeFormats = layerConfig.getMimeFormats();
        subLayer.setSourceFormat(mimeFormats != null ? mimeFormats[0] : null);
        insertGisLayer(subLayer);
    }

    @Override
    public void cleanLayerGroup(Long parentId) {
        if(0==parentId)return;
        GisLayer gisLayer = selectGisLayerByLayerId(parentId);
        if(gisLayer==null)return;
        GisLayer query = new GisLayer();
        query.setParentId(parentId);
        List<GisLayer> gisLayers = selectGisLayerList(query);
        if(gisLayers!=null&&gisLayers.size()>0)return;
        deleteGisLayerByLayerId(parentId);
        cleanLayerGroup(gisLayer.getParentId());
    }

    @Override
    public void updateRasterLayerStyle(GisLayer gisLayer, RasterStyleConfig config) {
        try {
            //参考文档：https://docs.geoserver.org/latest/en/user/styling/sld/reference/rastersymbolizer.html
            //geoserver 保存样式
            String styleName = config.getRenderType()+gisLayer.getLayerId();
            String styleBody = "";
            if(RasterStyleConfig.type_single.equals(config.getType())){
                styleBody = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
                        "<StyledLayerDescriptor version=\"1.0.0\" xmlns=\"http://www.opengis.net/sld\" xmlns:ogc=\"http://www.opengis.net/ogc\"" +
                        "                       xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"" +
                        "                       xsi:schemaLocation=\"http://www.opengis.net/sld http://schemas.opengis.net/sld/1.0.0/StyledLayerDescriptor.xsd\">" +
                        "  <NamedLayer>" +
                        "    <Name>"+styleName+"</Name>" +
                        "    <UserStyle>" +
                        "      <Name>"+styleName+"</Name>" +
                        "      <Title>"+styleName+"</Title>" +
                        "      <Abstract>"+styleName+"</Abstract>" +
                        "      <FeatureTypeStyle>" +
                        "        <Rule>" +
                        "          <RasterSymbolizer>" +
                        "            <Opacity>1.0</Opacity>" +
                        "            <ColorMap>" +
                        "              <ColorMapEntry color=\"" +config.getConfig().getLayerColor()+"\" quantity=\"-256\"  />" +
                        "              <ColorMapEntry color=\"" +config.getConfig().getLayerColor()+"\" quantity=\"256\"  />" +
//                        "              <ColorMapEntry color=\"" +config.getConfig().getLayerColorStart()+"\" quantity=\"256\" />" +
                        "            </ColorMap>" +
                        "          </RasterSymbolizer>" +
                        "        </Rule>" +
                        "      </FeatureTypeStyle>" +
                        "    </UserStyle>" +
                        "  </NamedLayer>" +
                        "</StyledLayerDescriptor>";
            }
            else if(RasterStyleConfig.type_gradient.equals(config.getType())){
                styleBody = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
                        "<StyledLayerDescriptor version=\"1.0.0\" xmlns=\"http://www.opengis.net/sld\" xmlns:ogc=\"http://www.opengis.net/ogc\"" +
                        "                       xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"" +
                        "                       xsi:schemaLocation=\"http://www.opengis.net/sld http://schemas.opengis.net/sld/1.0.0/StyledLayerDescriptor.xsd\">" +
                        "  <NamedLayer>" +
                        "    <Name>"+styleName+"</Name>" +
                        "    <UserStyle>" +
                        "      <Name>"+styleName+"</Name>" +
                        "      <Title>"+styleName+"</Title>" +
                        "      <Abstract>"+styleName+"</Abstract>" +
                        "      <FeatureTypeStyle>" +
                        "        <Rule>" +
                        "          <RasterSymbolizer>" +
                        "            <Opacity>1.0</Opacity>" +
                        "            <ColorMap>" ;
                for(ClassStyle style :config.getConfig().getRasters()){
                    styleBody +="              <ColorMapEntry color=\"" +style.getColor()+"\" quantity=\""+style.getQuantity()+"\"  />" ;
                }
                styleBody +="            </ColorMap>" +
                        "          </RasterSymbolizer>" +
                        "        </Rule>" +
                        "      </FeatureTypeStyle>" +
                        "    </UserStyle>" +
                        "  </NamedLayer>" +
                        "</StyledLayerDescriptor>";
            }
            else if(RasterStyleConfig.type_classification.equals(config.getType())){
                styleBody = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
                        "<StyledLayerDescriptor version=\"1.0.0\" xmlns=\"http://www.opengis.net/sld\" xmlns:ogc=\"http://www.opengis.net/ogc\"" +
                        "                       xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"" +
                        "                       xsi:schemaLocation=\"http://www.opengis.net/sld http://schemas.opengis.net/sld/1.0.0/StyledLayerDescriptor.xsd\">" +
                        "  <NamedLayer>" +
                        "    <Name>"+styleName+"</Name>" +
                        "    <UserStyle>" +
                        "      <Name>"+styleName+"</Name>" +
                        "      <Title>"+styleName+"</Title>" +
                        "      <Abstract>"+styleName+"</Abstract>" +
                        "      <FeatureTypeStyle>" +
                        "        <Rule>" +
                        "          <RasterSymbolizer>" +
                        "            <Opacity>1.0</Opacity>" +
                        "            <ColorMap>" ;
                for(ClassStyle style :config.getConfig().getRasters()){
                    styleBody +="              <ColorMapEntry color=\"" +style.getColor()+"\" quantity=\""+style.getQuantity()+"\"  label=\""+style.getLabel()+"\" />" ;
                }
                styleBody +="            </ColorMap>" +
                        "          </RasterSymbolizer>" +
                        "        </Rule>" +
                        "      </FeatureTypeStyle>" +
                        "    </UserStyle>" +
                        "  </NamedLayer>" +
                        "</StyledLayerDescriptor>";
            }
            else if(RasterStyleConfig.type_none.equals(config.getType())){
                styleBody = "";
            }
            if(!StringUtils.isEmpty(styleBody)){
                //背景 transparentColor
                geoserverService.updateCoverageConfig(gisLayer.getWorkspace(),
                        gisLayer.getLayerName(),
                        gisLayer.getLayerTitle(),gisLayer.getCrs(),config.getTransparentColor());
                boolean result = geoserverService.publishStyle(gisLayer.getWorkspace(), styleBody, styleName);
                if(result){
                    //更新样式
                    geoserverService.updateLayerStyle(gisLayer.getWorkspace(),
                            gisLayer.getLayerName(),styleName);
                    gisLayer.setRenderStyle(styleName);
                }
            }
            gisLayer.setSymbolization(JSON.toJSONString(config));
            updateGisLayer(gisLayer);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
